<template>
  <div class="affix">
    <div class="anchor">
      <div class="anchor__basic">
        <div class="anchor__basic-item" v-for="item in anchorList" :key="item.id" :class="{'active': item.id===id}"
             @click="local(item.id)">{{ item.name }}
        </div>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
import {defineComponent, onActivated, onDeactivated, PropType, reactive, toRefs, watch} from "vue";

interface ANCHORLIST { // 锚点列表
  id: string;
  name: string
}

interface STATE {
  id: string | undefined, // 当前的id
  anchorList: Array<ANCHORLIST> | undefined,
  timer: number,
}

export default defineComponent({
  props: {
    anchorList: {
      type: Array as PropType<ANCHORLIST[]>,
    },
    currentId: {
      type: String
    },
    offsetTop: { // 距离当前顶部高低
      type: String
    }
  },
  setup(props, ctx) {
    const state: STATE = reactive({
      id: props.currentId,
      anchorList: [],
      timer: 0,
    })
    watch(props, (val) => {
      state.anchorList = props.anchorList;
      state.id = props.currentId;
    })
    onActivated(() => {
      state.anchorList = props.anchorList;
      const personMessDetail: any = document.getElementsByClassName('ant-layout-content')[0]; // 获取滚动目标文档
      personMessDetail.addEventListener('scroll', handleScroll, false); // 添加监听滚动事件
    })
    onDeactivated(() => {
      const personMessDetail: any = document.getElementsByClassName('ant-layout-content')[0]
      personMessDetail.removeEventListener('scroll', handleScroll, false); // 移除监听滚动事件
    })
    /** 点击锚点 */
    const local = (type: string) => {
      const doc: any = document.querySelector(`#${type}`);
      let num = 0;
      const anchorList: any = state.anchorList;
      if (type === anchorList[0].id) { // 如果点击的为第一个id 滚动到顶部
        num = 0;
      } else {
        num = doc.offsetTop - 130 // 否则滚动到距离点击的id距离目标高度+130的位置
      }
      const personMessDetail: any = document.getElementsByClassName('ant-layout-content')[0]
      if (!personMessDetail.scrollTo) { // 目标文档滚动

        personMessDetail.scrollTop = num;
      } else {
        personMessDetail.scrollTo(0, num);
      }
      state.id = type;
    }
    /** 监听页面滚动 */
    const handleScroll = () => {
      if (state.timer) {
        clearTimeout(state.timer);
        state.timer = 0;
      }
      let list: any = [];
      // 获取每个id距离目标文档顶部的距离
      list = state.anchorList?.map(item => {
        return {
          id: item.id, option: (document.querySelector(`#${item.id}`) as any).offsetTop,
        }
      })
      const personMessDetail: any = document.getElementsByClassName('ant-layout-content')[0]
      state.timer = setTimeout(() => {
        const aa = Number(personMessDetail.scrollTop) + 230; // 滚动到目标位置则进行id切换， + 号后面的数据可根据自身进行加减
        if (aa < list[1].option) {
          state.id = list[0].id;
          return false;
        }
        for (var i = 0; i < list.length; i++) {
          if (list[i].option <= aa) {
            if (list[i].id !== state.id) {
              state.id = list[i].id;
            }
          }
        }
      }, 50)
    }
    return {
      ...toRefs(state),
      local
    }
  }
})
</script>
<style scoped lang="less">
.affix {
  position: fixed;
  width: 0;
  height: 0;
  top: 120px;

  .anchor {
    width: 160px;
    padding-left: 24px;

    &__basic {
      width: 160px;

    }

    &__basic-item {
      border-left: 3px solid #cccccc;
      padding-left: 12px;
      height: 32px;
      line-height: 32px;
      cursor: pointer;
    }

    .active {
      border-left: 3px solid #1890ff;
    }
  }
}

</style>
